<template>
  <WidgetContainer :data="data" class="app-group-widget" :class="{
                      'app-group-widget--drop-active': this.dropActive,
                      'app-group-widget--drop-enter': this.dropEnter,
                    }"
                   :context-menu="contextMenu" no-default-context-menu-item
  >
    <div class="full-width full-height" ref="container">
      <q-input class="app-title" filled v-model="folderTitle" dense>
        <template v-slot:append>
          <q-icon :color="showBadge?'green':''" class="cursor-pointer widget-header__append-icon"
                  name="badge"
                  @click="showBadge=!showBadge">
            <q-tooltip content-class="bg-primary" :offset="[10, 10]">显示点击次数等标记信息</q-tooltip>
          </q-icon>
          <q-icon :color="size==='xs'?'green':''" class="cursor-pointer widget-header__append-icon"
                  name="photo_size_select_small"
                  @click="size='xs'">
            <q-tooltip content-class="bg-primary" :offset="[10, 10]">小尺寸图标</q-tooltip>
          </q-icon>
          <q-icon :color="size==='sm'?'green':''" class="cursor-pointer widget-header__append-icon"
                  name="photo_size_select_large"
                  @click="size='sm'">
            <q-tooltip content-class="bg-primary" :offset="[10, 10]">中等尺寸图标</q-tooltip>
          </q-icon>
          <q-icon :color="size==='md'?'green':''" class="cursor-pointer widget-header__append-icon"
                  name="photo_size_select_actual"
                  @click="size='md'">
            <q-tooltip content-class="bg-primary" :offset="[10, 10]">大尺寸图标</q-tooltip>
          </q-icon>
          <q-icon class="cursor-pointer widget-header__append-icon"
                  name="add"
                  @click="createFormShow=true">
            <q-tooltip content-class="bg-primary" :offset="[10, 10]">添加新应用</q-tooltip>
          </q-icon>
        </template>
      </q-input>
      <div class="widget-grid" ref="appGrid">
        <grid-layout v-model:layout="renderApps" ref="gridLayout"
                     :col-num="colNum"
                     :max-rows="maxRow"
                     :min-rows="maxRow"
                     :row-height="rowHeight"
                     :prevent-collision="false"
                     :is-resizable="false"
                     :margin="[0,0]"
                     @drop-active="onDropActive"
                     @drag-enter="onDragEnter"
                     @drag-leave="onDragLeave"
                     @drop="onDrop"
                     @drop-deactivate="onDeactivate"
                     @layout-updated="onLayout"
                     style="width: 100%">
          <grid-item v-for="app in renderApps"
                     :key="app.id"
                     :id="app.id"
                     :h="app.h"
                     :w="app.w"
                     :y="app.y"
                     :x="app.x"
                     class="app-small-card-grid-item"
          >
            <app-small-card :data="app" :size="size" :key="app.id"
                            @remove="onRemoveApp" @moveOut="onMoveOut" @edit="onEdit(app)"
                            show-move-out class="absolute-center"
                            :click-badge="showBadge"
            >
            </app-small-card>
          </grid-item>
        </grid-layout>
      </div>
      <AppCardEditForm
          v-if="formShow"
          v-model="formData"
          v-model:show="formShow"
          :widget-id="data.id"
          mode="update"
      ></AppCardEditForm>
      <AppCardEditForm
          v-model:show="createFormShow"
          v-model="createFormData"
          :widget-id="data.id"
          mode="create"
      ></AppCardEditForm>
    </div>
  </WidgetContainer>
</template>

<script>
import AppCardEditForm from 'src/pages/workbench/widgets/management/AppCardEditForm'
import WidgetContainer from 'src/pages/workbench/components/WidgetContainer'
import { cloneDeep, isNumber, isUndefined } from 'lodash'
import AppSmallCard from '../components/AppSmallCard'
import { GridItem, GridLayout } from '../../../components/grid'
import { LayoutEngine } from '../../../utils/widget'

export default {
  name: 'AppGroupWidget',
  components: {
    AppSmallCard,
    AppCardEditForm,
    WidgetContainer,
    GridLayout,
    GridItem
  },
  props: {
    data: Object
  },
  data () {
    this.layoutEngine = new LayoutEngine()
    return {
      folderTitle: this.data.title,
      isMouseHover: false,
      formData: {
        appData: {}
      },
      // 新增表单
      createFormShow: false,
      createFormData: {
        appData: {}
      },
      currentApp: null,
      size: this.data.size || 'md',
      showBadge: this.data.showBadge,
      renderApps: [],
      // 拖拽交互
      dropActive: false,
      dropEnter: false,
      margin: [5, 5],
      headerHeight: 40,
      widgetH: this.data.h,
      // 内部应用编辑新增
      formShow: false,
      contextMenu: [
        {
          label: '删除分组',
          onClick: this.removeFolder
        }
      ]
    }
  },
  computed: {
    sizeWidth () {
      return {
        xs: 77,
        sm: 96,
        md: 115
      }[this.size] || 115
    },
    sizeHeight () {
      return {
        xs: 90,
        sm: 112,
        md: 135
      }[this.size] || 115
    },
    colNum () {
      return Math.floor(this.data.w * 116 / this.sizeWidth)
    },
    maxRow () {
      return Math.floor((this.data.h * 116 - this.headerHeight - this.margin[1] * 2) / this.sizeHeight)
    },
    rowHeight () {
      return (this.data.h * 116 - this.headerHeight - this.margin[1] * 2) / this.maxRow
    }
  },
  watch: {
    folderTitle () {
      this.updateWidget()
    },
    showBadge () {
      this.updateWidget()
    },
    size () {
      this.updateH()
      this.rearrange()
      this.updateWidget()
    },
    'data.w' () {
      this.rearrange()
      this.updateWidget()
    },
    'data.h' () {
      this.widgetH = this.data.h
    },
    'data.apps': {
      handler (newApps, oldApps) {
        console.log(`=> AppGroup onLayout - ${this.data.id}`)
        let retainApps = []
        let needUpdateWidget = false

        // 格式化新 APP -> w.h.x.y
        this.layoutEngine.clearCache()
        const newAppFormat = app => {
          needUpdateWidget = true
          const pos = this.layoutEngine.getSpacePos(1, 1, {
            cache: true,
            column: this.colNum,
            positions: retainApps
          })
          return {
            ...app,
            ...pos,
            w: 1,
            h: 1
          }
        }

        // 第一次赋值的情况
        // - 组件数据初始化
        // - 两个应用组件合并
        if (!oldApps) {
          retainApps = newApps.filter(app => {
            return isNumber(app.w) &&
                isNumber(app.h) &&
                isNumber(app.x) &&
                isNumber(app.y)
          })
          this.renderApps = cloneDeep(newApps.map(app => {
            if (isUndefined(app.w) ||
                isUndefined(app.h) ||
                isUndefined(app.x) ||
                isUndefined(app.y)) {
              return newAppFormat(app)
            }
            return app
          }))
          needUpdateWidget && this.updateWidget()
          return
        }

        // 应用组改变的情况
        // 1. 新增应用
        // 2. 移除应用
        // 3. 新增并移除应用
        const appendApps = newApps.filter(newApp => {
          return !oldApps.find(e => e.id === newApp.id) ||
              isUndefined(newApp.w) ||
              isUndefined(newApp.h) ||
              isUndefined(newApp.x) ||
              isUndefined(newApp.y)
        })
        retainApps = newApps.filter(newApp => !appendApps.find(e => e.id === newApp.id))
        const removedApps = oldApps.filter(oldApp => !newApps.find(e => e.id === oldApp.id))

        // console.log('newApps', stringifyApps(newApps));
        // console.log('oldApps', stringifyApps(oldApps));
        // console.log('appendApps', stringifyApps(appendApps));
        // console.log('removedApps', stringifyApps(removedApps));
        // console.log('retainApps', stringifyApps(retainApps));

        if (removedApps.length === 0 && appendApps.length === 0) {
          this.renderApps = cloneDeep(newApps)
        } else {
          this.renderApps = cloneDeep([
            ...retainApps,
            // 新增应用校验并矫正格式 - 从应用组件合并的情况
            ...appendApps.map(app => newAppFormat(app))
          ])
          // console.log(this.colNum * this.maxRow, this.renderApps.length);
          this.updateH()
          needUpdateWidget && this.updateWidget()
        }
      },
      immediate: true,
      deep: true
    }
  },
  methods: {
    rearrange () {
      this.renderApps = this.renderApps.map(e => {
        const pos = this.layoutEngine.getNextPos(1, 1, {
          cache: true,
          column: this.colNum
        })
        return {
          ...e,
          ...pos
        }
      })
    },
    updateH () {
      if (this.colNum * this.maxRow < this.renderApps.length) {
        this.widgetH = this.data.h +
            Math.max(
                1,
                Math.ceil((this.renderApps.length - this.colNum * this.maxRow) / this.colNum)
            )
      }
    },
    updateWidget () {
      const widget = cloneDeep(this.data)
      widget.apps = cloneDeep(this.renderApps)
      widget.title = this.folderTitle
      widget.size = this.size
      widget.showBadge = this.showBadge
      widget.h = this.widgetH
      this.$store.dispatch('widget/updateWidget', widget)
    },
    onLayout () {
      console.log(`<= AppGroup onLayout - ${this.data.id}`)
      this.updateWidget()
      this.$nextTick(() => {
        this.$refs.gridLayout?.eventBus.emit('resizeEvent')
      })
    },
    async onRemoveApp (app) {
      if (app.type === 1) {
        await this.$store.dispatch('widget/removeCollectionApp', app)
      }
      if (app.type === 2) {
        await this.$store.dispatch('widget/removeCustomApps', [app])
      }
    },
    async removeFolder () {
      await this.$store.dispatch('widget/removeCustomApps', this.data.apps)
      await this.$store.dispatch('widget/removeCollectionApps', this.data.apps)
    },
    onMoveOut (app) {
      this.$store.dispatch('widget/moveOutAppFromWidget', {
        appId: app.id,
        widgetId: this.data.id
      })
    },
    onEdit (app) {
      this.formData = Object.assign({}, app)
      this.formShow = true
    },
    onDropActive () {
      this.dropActive = true
    },
    onDragEnter () {
      this.dropEnter = true
    },
    onDragLeave () {
      this.dropEnter = false
    },
    onDrop (event) {
      const appId = event.relatedTarget.id
      const matchApp = this.renderApps.find(e => e.id === appId)
      if (matchApp) return
      // 滞后调用 - 因为
      this.$nextTick(() => {
        this.$store.dispatch('widget/transferAppWidget', {
          targetWidgetId: this.data.id,
          appId
        })
      })
    },
    onDeactivate () {
      this.dropActive = false
      this.dropEnter = false
    }
  }
}
</script>

<style lang="scss">

.app-group-widget {
  transition: all 200ms;

  &--shadow {
    box-shadow: 0 1px 5px rgb(0 0 0 / 20%), 0 2px 2px rgb(0 0 0 / 14%), 0 3px 1px -2px rgb(0 0 0 / 12%);
    border-radius: 2px;
  }

  .app-title {
    &__append-icon {
      visibility: hidden;
      transition: 0.3ms;
      opacity: 0;
    }
  }

  &:hover {
    .app-title {
      &__append-icon {
        visibility: visible;
        opacity: 1;
      }
    }
  }

  &--drop-active {

  }

  &--drop-enter {
    box-shadow: 0 0 0 5px #A0A0A0, inset 0 10px 27px -8px #141414, inset 0px -10px 27px -8px #A31925, 5px 5px 15px 5px rgba(0, 0, 0, 0);
  }
}

</style>
